/*
 * MovingObject.cpp
 *
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses 
 */

#include "MovingObject.h"
#include "MapObject.h"
#include "ModelConstants.h"
#include <algorithm>

MovingObject::MovingObject(int x, int y)
    : LivingObject(x, y) {
    init();
}

MovingObject::MovingObject(int id, int x, int y)
    : LivingObject(id, x, y) {
    init();
}

void MovingObject::init() {
    last_x = x;
    last_y = y;
    speed = 0;
    mov_strategy = 0;
    direction = NO_DIRECTION;
    tics_since_moved = 0;
}

int MovingObject::getLastX() {
    return last_x;
}

int MovingObject::getLastY() {
    return last_y;
}

int MovingObject::getDirection() {
    return direction;
}

void MovingObject::setDirection(int direction) {
    this->direction = direction;
}

void MovingObject::live(Map& map) {
    move(map);
}

void MovingObject::move(Map& map) {
    if (mov_strategy != 0) {
        if (tics_since_moved < speed) {
            tics_since_moved++;
        } else {
            if (isDestroyed()) {
                return;
            }
            mov_strategy->resolveMoveDirection(map);
            if (nextMoveIsInvalid(map)) {
                mov_strategy->resolveInvalidMove(map);
            }
            advance(map);
            notify(OBJECT_MOVED, this);
            tics_since_moved = 0;
        }
    }
}

bool MovingObject::nextMoveIsInvalid(Map& map) {
    int new_x = getNextX();
    int new_y = getNextY();
    return ! map.isValidPosition(new_x, new_y);
}

void MovingObject::turnAround() {
    if (direction != NO_DIRECTION) {
        direction*= -1;
    }
}

void MovingObject::advance(Map& map) {
    int new_x = getNextX();
    int new_y = getNextY();
    std::swap(x, last_x);
    std::swap(y, last_y);
    x = new_x;
    y = new_y;
    if (map.insertObject(this, new_x, new_y)) {
        map.removeObject(last_x, last_y);
    } else {
        std::swap(x, last_x);
        std::swap(y, last_y);
        turnAround();
    }
}

void MovingObject::revertMove(Map& map) {
    std::swap(x, last_x);
    std::swap(y, last_y);
    turnAround();
    map.insertObject(this, x, y);
}

MovingObject::~MovingObject() {
    delete(mov_strategy);
}

int MovingObject::getNextX() {
    if (direction == RIGHT) {
        return x+1;
    } else if (direction == LEFT) {
        return x-1;
    } else {
        return x;
    }
}

int MovingObject::getNextY() {
    if (direction == UP) {
        return y-1;
    } else if (direction == DOWN) {
        return y+1;
    } else {
        return y;
    }
}
